package com.douya.mvc.aop;

import cn.hutool.json.JSONUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 缓存注解切面
 *
 * @Author hcy
 * @Date 2024/4/2  15:26
 */
@Aspect
@Component
public class CacheAspect {

    @Resource
    private RedissonClient redissonClient;

    @Value("${spring.application.name}")
    private String applicationName;

    @Around("@annotation(Cacheable)")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        Cacheable cacheable = method.getAnnotation(Cacheable.class);
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String queryString = request.getQueryString();
        String key = request.getRequestURI() + (queryString == null ? "" : "?" + queryString);
        long expireTime = cacheable.expireTime();
        TimeUnit timeUnit = cacheable.timeUnit();
        RMapCache<String, Object> mapCache = redissonClient.getMapCache(applicationName + "-cache");
        if (mapCache.containsKey(key)) {
            String json = (String) mapCache.get(key);
            return JSONUtil.toBean(json, method.getReturnType());
        }
        Object result = pjp.proceed();
        mapCache.put(key, JSONUtil.toJsonStr(result), expireTime, timeUnit);
        return result;
    }
}